package com.topisv.tms.service.stock;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.persistence.DynamicSpecifications;
import org.springside.modules.persistence.SearchFilter;
import org.springside.modules.persistence.SearchFilter.Operator;

import com.topisv.tms.entity.AreaGroup;
import com.topisv.tms.entity.Customers;
import com.topisv.tms.entity.EdiGoodsSku;
import com.topisv.tms.entity.QueryParamHolder;
import com.topisv.tms.entity.log.StockMoveLog;
import com.topisv.tms.entity.stock.CusStock;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.repository.AreaGroupDao;
import com.topisv.tms.repository.CustomersDao;
import com.topisv.tms.repository.EdiGoodsSkuDao;
import com.topisv.tms.repository.log.StockMoveLogDao;
import com.topisv.tms.repository.stock.CusStockDao;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.tools.StringCusUtils;
import com.topisv.tms.utils.PubUtil;

/**
 * 商家库存_service
 * 
 * @author ch
 *
 */
@Component
@Transactional(readOnly = true)
public class CusStockService extends BaseService {

	@Autowired
	private CusStockDao cusStockDao;
	@Autowired
	private EdiGoodsSkuDao ediGoodsSkuDao;
	@Autowired
	private CustomersDao customersDao;
	@Autowired
	private AreaGroupDao areaGroupDao;
	@Autowired
	private StockMoveLogDao stockMoveLogDao;
	@PersistenceContext
	private EntityManager em;

	/**
	 * 查找库位信息
	 * 
	 * @param warehouseCode
	 *            仓库编码
	 * @param customerCode
	 *            商家编码
	 * @param sku
	 *            sku号
	 * @return
	 */
	public List<CusStock> loadStock(String warehouseCode, String customerCode, String sku) {
		return this.cusStockDao.loadStock(warehouseCode, customerCode, sku);
	}

	/**
	 * 查找库位信息
	 * 
	 * @param customerCode
	 *            商家编码
	 * @param sku
	 *            sku号
	 * @return
	 */
	public List<CusStock> loadStock(String customerCode, String sku) {
		return this.cusStockDao.loadStock(customerCode, sku);
	}

	/**
	 * 查找箱子信息
	 * 
	 * @param warehouseCode
	 *            仓库编码
	 * @param customerCode
	 *            商户编码
	 * @param boxCode
	 *            箱编码
	 * @return
	 */
	public List<CusStock> loadStockByBoxCode(String warehouseCode, String customerCode, String boxCode) {
		return this.cusStockDao.loadStockByBoxCode(warehouseCode, customerCode, boxCode);
	}

	/**
	 * 查询库位信息
	 * 
	 * @param customerCode
	 *            商户编码
	 * @param warehouseCode
	 *            仓库编码
	 * @param stockCode
	 *            库位编码
	 * @param boxCode
	 *            箱子编码
	 * @param sku
	 *            SKU编码
	 * @return
	 */
	public List<CusStock> findStockByParam(Map<String, Object> param) {

		Specification<CusStock> spec = this.getWhereClause(param);
		List<CusStock> list = this.cusStockDao.findAll(spec);

		for (CusStock cusStock : list) {
			this.setDetail(cusStock);
		}
		return list;
	}

	/**
	 * 封装查询参数
	 * 
	 * @param param
	 * @return
	 */
	private Specification<CusStock> getWhereClause(final Map<String, Object> param) {
		return new Specification<CusStock>() {

			@Override
			public Predicate toPredicate(Root<CusStock> r, CriteriaQuery<?> q, CriteriaBuilder cb) {

				Predicate pre = cb.conjunction();

				/*
				 * String customerCode=(String)param.get("customerCode");
				 * if(StringUtils.isNotBlank(customerCode)){
				 * pre.getExpressions()
				 * .add(cb.equal(r.<String>get("customerCode"), customerCode));
				 * }
				 */

				// customerCode
				String customerCodes = (String) param.get("customerCode");
				if (StringUtils.isNotBlank(customerCodes)) {
					String[] customerCodeSplit = customerCodes.split(":");
					ComparisonPredicate[] tempCustomerCode = new ComparisonPredicate[customerCodeSplit.length];
					int i = 0;
					for (String _customerCode : customerCodeSplit) {
						tempCustomerCode[i] = (ComparisonPredicate) cb.equal(r.<String> get("customerCode"), _customerCode);
						i++;
					}
					pre.getExpressions().add(cb.or(tempCustomerCode));
				}

				String warehouseCode = (String) param.get("warehouseCode");
				if (StringUtils.isNotBlank(warehouseCode)) {
					pre.getExpressions().add(cb.equal(r.<String> get("warehouseCode"), warehouseCode));
				}

				String stockCode = (String) param.get("stockCode");
				if (StringUtils.isNotBlank(stockCode)) {
					pre.getExpressions().add(cb.equal(r.<String> get("stockCode"), stockCode));
				}

				String boxCode = (String) param.get("boxCode");
				if (StringUtils.isNotBlank(boxCode)) {
					pre.getExpressions().add(cb.equal(r.<String> get("boxCode"), boxCode));
				}

				String sku = (String) param.get("sku");
				if (StringUtils.isNotBlank(sku)) {
					pre.getExpressions().add(cb.equal(r.<String> get("sku"), sku));
				}

				return pre;
			}

		};
	}

	/**
	 * 保存库位信息
	 * 
	 * @param stock
	 */
	@Transactional(readOnly = false)
	public void saveStock(CusStock stock) {
		this.cusStockDao.save(stock);
	}

	/**
	 * 查询库位信息
	 * 
	 * @param customerCode
	 *            商家编码
	 * @param warehouseCode
	 *            仓库编码
	 * @param sku
	 *            SKU编码
	 * @return
	 */
	public List<CusStock> loadStockByCondition(String customerCode, String warehouseCode, String sku) {
		return this.cusStockDao.loadStockByCondition(customerCode, warehouseCode, sku);
	}

	/**
	 * 查询库位信息
	 * 
	 * @param customerCode
	 *            商家编码
	 * @param warehouseCode
	 *            仓库编码
	 * @param stockCode
	 *            库位编码
	 * @param pageNumber
	 * @param pageSize
	 * @return
	 */
	public Page<CusStock> loadStock(String customerCode, String warehouseCode, String stockCode, String boxCode, String boxType, int pageNumber, int pageSize) {
		Map<String, SearchFilter> filters = new HashMap<String, SearchFilter>();
		if (null != customerCode && !"".equals(customerCode)) {
			filters.put("customerCode", new SearchFilter("customer.customerCode", Operator.EQ, customerCode));
		}
		if (null != warehouseCode && !"".equals(warehouseCode)) {
			filters.put("warehouseCode", new SearchFilter("warehouseCode", Operator.EQ, warehouseCode));
		}
		if (null != stockCode && !"".equals(stockCode)) {
			filters.put("stockCode", new SearchFilter("stockCode", Operator.LIKE, "%" + stockCode + "%"));
		}

		if (null != boxCode && !"".equals(boxCode)) {
			filters.put("boxCode", new SearchFilter("boxCode", Operator.LIKE, "%" + boxCode + "%"));
		}

		if (null != boxType && !"".equals(boxType)) {
			if ("common".equals(boxType)) {
				filters.put("boxType", new SearchFilter("boxType", Operator.EQ, null));
			} else if ("prepkg".equals(boxType)) {
				filters.put("boxType", new SearchFilter("boxType", Operator.EQ, boxType));
			}
		}

		PageRequest pageRequest = buildPageRequest(pageNumber, pageSize);
		Specification<CusStock> spec = DynamicSpecifications.bySearchFilter(filters.values(), CusStock.class);
		Page<CusStock> page = this.cusStockDao.findAll(spec, pageRequest);

		List<CusStock> stockList = page.getContent();
		for (CusStock cusStock : stockList) {
			this.setDetail(cusStock);
		}

		return page;
	}

	public void setDetail(CusStock stock) {

		String sku = stock.getSku();
		String customerCode = stock.getCustomerCode();
		EdiGoodsSku goods = this.ediGoodsSkuDao.findByCustomerCodeAndSku(customerCode, sku);
		if (goods != null) {
			stock.setBar(goods.getBar());
			stock.setSpec(goods.getSpec());
			stock.setGoodsName(goods.getSkuName());
		}

		// warehouse
		String warehouseCode = stock.getWarehouseCode();
		AreaGroup warehouse = this.areaGroupDao.findByGroupCode(warehouseCode);
		stock.setWarehouse(warehouse);

	}

	private PageRequest buildPageRequest(int pageNumber, int pagzSize) {
		String[] sorts = { "customer.customerCode", "warehouseCode", "stockCode", "sku" };
		Sort sort = new Sort(Direction.ASC, sorts);
		return new PageRequest(pageNumber - 1, pagzSize, sort);
	}

	public List<CusStock> loadByStockCode(String stockCode) {
		return this.cusStockDao.loadByStockCode(stockCode);
	}

	/**
	 * 同步仁清库存数据
	 * 
	 * @param rightList
	 * @throws Exception
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void synStockForLKE(List<String[]> rightList) throws Exception {
		try {

			// 删除之前的数据
			List<CusStock> list_old = this.cusStockDao.loadByCustomerCode("LKE");
			this.cusStockDao.delete(list_old);

			// 添加新的数据
			List<CusStock> list = new ArrayList<CusStock>();
			Customers customer = this.customersDao.findByCustomerCode("LKE");

			for (String[] str : rightList) {
				String _boxCode = str[0];
				String _sku = str[1];
				String _salesNum = str[2];
				String _stockCode = str[3];

				CusStock stock = new CusStock();
				stock.setCustomerCode("LKE");
				stock.setWarehouseCode("LKE");
				stock.setStockCode(_stockCode);
				stock.setBoxCode(_boxCode);
				stock.setSku(_sku);
				stock.setCustomer(customer);
				stock.setSalesNum(Integer.valueOf(_salesNum));
				stock.setLastmodifyTime(new Date());

				stock.setAirNum(0);
				stock.setLockedNum(0);
				stock.setOrderNum(0);
				stock.setTransportNum(0);
				stock.setUnusedNum(0);

				list.add(stock);
			}
			this.cusStockDao.save(list);
		} catch (Exception e) {
			throw e;
		}
	}

	public Page<CusStock> findCusStock(QueryParamHolder paramHolder) {
		return findByJson(paramHolder, cusStockDao, CusStock.class);
	}

	/**
	 * 移动库位
	 * 
	 * @param from
	 * @param to
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public String move(CusStock from, CusStock to) {
		String rs = "true";
		// 校验原始库位是否有订单占用
		CusStock fromStock = checkStock(from);
		if (fromStock == null) {
			rs = "notExist";
		} else if (fromStock.getOrderNum() > 0) {
			rs = "takeup";
		} else if (!(fromStock.getSalesNum() == null ? from.getSalesNum() == null : fromStock.getSalesNum().intValue() == from.getSalesNum().intValue())) {
			rs = "numNotMatch";
		} else {
			// EditBy yinglei_lian 2016.09.27
			//CusStock checkCusStock = checkMoveToOtherStock(to);// 有其他库存 并且数量为位0
																// 或者有相同商品
																// 但是批次不同并且数量不为0
//			if (checkCusStock != null)
//				throw new PaiUException(ErrorCode.REDO_INSTORAGE_UP_DISPATCH_TASK, new String[] { checkCusStock.getSku() + "SKU、批次号、生产日期、过期日期不匹配" });

			CusStock toStock = checkStock(to);

			if (toStock == null) {
				List<CusStock> stockList = this.cusStockDao.loadStockNew(to.getCustomerCode(), to.getWarehouseCode(), to.getStockCode(), to.getBoxCode());

				for (CusStock stock2 : stockList) {
					//if (!(stock2.getSku().equals(fromStock.getSku())) || !((stock2.getBatchCode() == null ? "" : stock2.getBatchCode()).equals(fromStock.getBatchCode() == null ? "" : fromStock.getBatchCode())) || !((stock2.getProductDate() == null ? "" : stock2.getProductDate()).equals(fromStock.getProductDate() == null ? "" : fromStock.getProductDate())) || !((stock2.getExpireDate() == null ? "" : stock2.getExpireDate()).equals(fromStock.getExpireDate() == null ? "" : fromStock.getExpireDate()))) {
					if (!(stock2.getSku().equals(fromStock.getSku())) ) {
						
//					if ((stock2.getSalesNum() + stock2.getUnusedNum() + stock2.getOrderNum() + stock2.getLockedNum() + stock2.getTransportNum() + stock2.getAirNum()) != 0) {
//							throw new PaiUException(ErrorCode.REDO_INSTORAGE_UP_DISPATCH_TASK, new String[] { stock2.getSku() + "SKU、批次号、生产日期、过期日期不匹配" });
//						}
						
					} else {
						toStock = stock2;
						break;
					}
				}
			}

			if (toStock == null) {

				toStock = new CusStock();
				toStock.setBoxCode(to.getBoxCode());
				toStock.setStockCode(to.getStockCode());
				toStock.setSku(fromStock.getSku());
				toStock.setBatchCode(fromStock.getBatchCode());
				toStock.setProductDate(fromStock.getProductDate());
				toStock.setExpireDate(fromStock.getExpireDate());
				toStock.setStockType(fromStock.getStockType());
				toStock.setBoxType(fromStock.getBoxType());
				toStock.setCustomerCode(fromStock.getCustomerCode());
				Customers customer = this.customersDao.findByCustomerCode(fromStock.getCustomerCode());
				toStock.setCustomer(customer);
				toStock.setWarehouseCode(fromStock.getWarehouseCode());
				toStock.setSalesNum(0);
				toStock.setUnusedNum(0);
				toStock.setOrderNum(0);
				toStock.setLockedNum(0);
				toStock.setTransportNum(0);
				toStock.setAirNum(0);
				toStock.setLastmodifyTime(new Date());
				// toStock.setLastmodifyTime(fromStock.getLastmodifyTime());

			}

			fromStock.setSalesNum(fromStock.getSalesNum() - to.getSalesNum());
			toStock.setSalesNum(toStock.getSalesNum() + to.getSalesNum());
			cusStockDao.save(fromStock);
			cusStockDao.save(toStock);
			// 记录移动日志
			StockMoveLog log = new StockMoveLog();
			log.setOperateName(getShiroUser().getRealname());
			log.setOperateTm(new Date());
			log.setCustomerCode(from.getCustomerCode());
			log.setWarehouseCode(from.getWarehouseCode());
			log.setSku(from.getSku());
			log.setSkuNum(to.getSalesNum());
			log.setFromStockCode(from.getStockCode());
			log.setFromBoxCode(from.getBoxCode());
			log.setToStockCode(to.getStockCode());
			log.setToBoxCode(to.getBoxCode());
			log.setErrorFlag("noterror");
			stockMoveLogDao.save(log);
		}
		return rs;
	}

	/**
	 * 检查是否有订单占用.
	 * 
	 * @param from
	 */
	private CusStock checkStock(CusStock from) {
		// return
		// cusStockDao.loadStock(from.getCustomerCode(),from.getWarehouseCode(),from.getStockCode(),from.getBoxCode(),from.getSku());
		return cusStockDao.loadStockNew2(from.getCustomerCode(), from.getWarehouseCode(), from.getStockCode(), from.getBoxCode(), from.getSku(), from.getBatchCode(), from.getProductDate(), from.getExpireDate());
	}

	/**
	 * 检查to的库位上是否有其他商品
	 * 
	 * @param to
	 * @return
	 */
	private CusStock checkMoveToOtherStock(CusStock to) {
//		List<CusStock> cusStocks = cusStockDao.LoadOtherStock(to.getCustomerCode(), to.getWarehouseCode(), to.getStockCode(), to.getBoxCode(), to.getSku());// 判断是否有其他商品
//		if (cusStocks != null && cusStocks.size()>0)
//			return cusStocks.get(0);// 有其他商品 不能移库
		// 有没相同商品 但是批次、时间不同的商品
		if ((PubUtil.isNotEmpty(to.getBatchCode()) || PubUtil.isNotEmpty(to.getProductDate()) || PubUtil.isNotEmpty(to.getExpireDate()))) {// 有有效期管理
			List<CusStock> stockList = this.cusStockDao.loadStockNew(to.getCustomerCode(), to.getWarehouseCode(), to.getStockCode(), to.getBoxCode());
			for (CusStock stock2 : stockList) {
				if ((stock2.getSku().equals(to.getSku())) && (!(stock2.getBatchCode() == null ? "" : stock2.getBatchCode()).equals(to.getBatchCode() == null ? "" : to.getBatchCode())) || !((stock2.getProductDate() == null ? "" : stock2.getProductDate()).equals(to.getProductDate() == null ? "" : to.getProductDate())) || !((stock2.getExpireDate() == null ? "" : stock2.getExpireDate()).equals(to.getExpireDate() == null ? "" : to.getExpireDate()))) {
					if ((stock2.getSalesNum() + stock2.getUnusedNum() + stock2.getOrderNum() + stock2.getLockedNum() + stock2.getTransportNum() + stock2.getAirNum()) != 0) {
						return stock2;
					}
				}
			}
		}
		return null;
	}

	/**
	 * 不良品移动库位
	 * 
	 * @param from
	 * @param to
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public String faultyMove(CusStock from, CusStock to) {
		String rs = "true";
		// 校验原始库位是否有订单占用
		CusStock fromStock = checkStock(from);
		if (fromStock == null) {
			rs = "notExist";
		} else if (fromStock.getOrderNum() > 0) {
			rs = "takeup";
		} else if (!(fromStock.getUnusedNum() == null ? from.getUnusedNum() == null : fromStock.getUnusedNum().intValue() == from.getUnusedNum().intValue())) {
			rs = "numNotMatch";
		} else {
			CusStock toStock = checkStock(to);
			if (toStock == null) {
				toStock = new CusStock();
				toStock.setBoxCode(to.getBoxCode());
				toStock.setStockCode(to.getStockCode());
				toStock.setSku(fromStock.getSku());
				toStock.setStockType(fromStock.getStockType());
				toStock.setBoxType(fromStock.getBoxType());
				toStock.setCustomerCode(fromStock.getCustomerCode());
				Customers customer = this.customersDao.findByCustomerCode(fromStock.getCustomerCode());
				toStock.setCustomer(customer);
				toStock.setWarehouseCode(fromStock.getWarehouseCode());
				toStock.setSalesNum(0);
				toStock.setUnusedNum(0);
				toStock.setOrderNum(0);
				toStock.setLockedNum(0);
				toStock.setTransportNum(0);
				toStock.setAirNum(0);
				toStock.setLastmodifyTime(new Date());
			}

			fromStock.setUnusedNum(fromStock.getUnusedNum() - to.getUnusedNum());
			toStock.setUnusedNum(toStock.getUnusedNum() + to.getUnusedNum());
			cusStockDao.save(fromStock);
			cusStockDao.save(toStock);
			// 记录移动日志
			StockMoveLog log = new StockMoveLog();
			log.setOperateName(getShiroUser().getRealname());
			log.setOperateTm(new Date());
			log.setCustomerCode(from.getCustomerCode());
			log.setWarehouseCode(from.getWarehouseCode());
			log.setSku(from.getSku());
			log.setSkuNum(to.getUnusedNum());
			log.setFromStockCode(from.getStockCode());
			log.setFromBoxCode(from.getBoxCode());
			log.setToStockCode(to.getStockCode());
			log.setToBoxCode(to.getBoxCode());
			log.setErrorFlag("error");
			stockMoveLogDao.save(log);
		}
		return rs;
	}

	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public String lock(List<Long> stocks) {
		cusStockDao.lockStock(stocks);
		return "true";
	}

	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public String unLock(List<Long> stocks) {
		cusStockDao.unLockStock(stocks);
		return "true";
	}

	/**
	 * 单独的事务更新库存并记录数据，用于后期手工回滚（if possible）
	 *
	 * @param customerCode
	 * @param warehouseCode
	 * @param batchCode
	 * @param orderNo
	 * @param stockCode
	 * @param boxCode
	 * @param sku
	 * @param num
	 *            [参数说明]
	 * @author <a href=mailto:yuanlianghe@nryuncang.com>yuanlianghe</a>
	 * @since 2016-09-20
	 */
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void updateCusStock4CreateTask(String customerCode, String warehouseCode, String batchCode, String orderNo, String stockCode, String boxCode, String sku, int num) {
		Query query = em.createNativeQuery("update cus_stock set sales_num=sales_num-?, order_num=order_num+?, version=version+? " + "where customer_code=? and warehouse_code=? and stock_code=? and box_code=? and sku=? and sales_num>=? limit ?");
		int i = 1;
		query.setParameter(i++, num);
		query.setParameter(i++, num);
		query.setParameter(i++, 1);
		query.setParameter(i++, customerCode);
		query.setParameter(i++, warehouseCode);
		query.setParameter(i++, stockCode);
		query.setParameter(i++, boxCode);
		query.setParameter(i++, sku);
		query.setParameter(i++, num);
		query.setParameter(i++, 1);

		int cnt = query.executeUpdate();
		if (cnt == 0) {
			throw new RuntimeException("库存不能满足，订单号：" + orderNo + "  sku:" + sku);
		}

		query = em.createNativeQuery("insert into cus_stock_task_rollback(customer_code, warehouse_code, stock_code, box_code, sku, batch_code, order_no, num, status, created_time) values (?,?,?,?,?,?,?,?,?,?)");
		i = 1;
		query.setParameter(i++, customerCode);
		query.setParameter(i++, warehouseCode);
		query.setParameter(i++, stockCode);
		query.setParameter(i++, boxCode);
		query.setParameter(i++, sku);
		query.setParameter(i++, batchCode);
		query.setParameter(i++, orderNo);
		query.setParameter(i++, num);
		query.setParameter(i++, 0);
		query.setParameter(i++, new Date());
		query.executeUpdate();
	}

}
